package com.objects;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Vector;
import java.util.concurrent.Semaphore;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import com.data.Point3D;
import com.main.Railway;
import com.main.TrainFrame;
import com.panels.cell.ValuePair;


public class Wagon {

	public 	double semiLen=0;
	public 	double semiWidth=0;

	public 	double fi=0;
	public 	double omega=0;

	public 	Point3D cm=null;
	public  Point3D vcm=null;

	public  double mass=10; 
	public 	double INVERSE_I=1;
	public Railway rw=null;

	public BufferedImage wagonImage;
	public int wagon_type=0;
	
	public static Wagon[] WAGONS_DATA=null;
	
	public static double link_distance=20;
	
	static{
		
		
		try {
			loadWagonsImages();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	public Wagon() {

		
	}

	public Wagon(Railway railway) {
		this.rw=railway;
		
		this.cm=new Point3D(0,0,0);
		this.vcm=new Point3D(0,0,0);

		this.wagonImage=WAGONS_DATA[this.wagon_type].wagonImage;
		this.semiLen=WAGONS_DATA[this.wagon_type].semiLen;
		this.semiWidth=WAGONS_DATA[this.wagon_type].semiWidth;
		
		INVERSE_I=12.0/(4*semiLen*semiLen*mass);
	}
	

	protected Object clone() throws CloneNotSupportedException {
	
		
		Wagon w=new Wagon();
		w.rw=rw;
		
		w.cm=this.cm;
		w.vcm=this.vcm;
		w.fi=fi;
		
		w.wagon_type=wagon_type;
		
		w.wagonImage=this.wagonImage;
		w.semiLen=this.semiLen;
		w.semiWidth=this.semiWidth;
		
		w.INVERSE_I=INVERSE_I;
		
		return w;
	}

	private static void loadWagonsImages() throws IOException {
		
		
		File directoryImg=new File("lib/wagons");
		File[] files=directoryImg.listFiles();
		
		Vector vImages=new Vector();
		
		for(int i=0;i<files.length;i++){
			if(files[i].getName().startsWith("wagon_")){
				
				
				BufferedImage img = ImageIO.read(files[i]);
				vImages.add(img);
				
			}		
		}
		
		WAGONS_DATA=new Wagon[vImages.size()];
		
		for (int i = 0; i < vImages.size(); i++) {
			
			WAGONS_DATA[i] = new Wagon();
			WAGONS_DATA[i].wagonImage= (BufferedImage) vImages.elementAt(i);
			WAGONS_DATA[i].semiWidth=WAGONS_DATA[i].wagonImage.getHeight()/2.0;
			WAGONS_DATA[i].semiLen=WAGONS_DATA[i].wagonImage.getWidth()/2.0;
			
			WAGONS_DATA[i].wagon_type=i;
		}
		
		
	}

	public Point3D getFrontCenter(){

		double sinf=Math.sin(fi);
		double cosf=Math.cos(fi);	

		return new Point3D(cm.x+semiLen*cosf,cm.y+semiLen*sinf,0);

	}

	public void move() {

		cm.x+=rw.dt*vcm.x;
		cm.y+=rw.dt*vcm.y;			

		//System.out.println(Math.sqrt(vcm.x*vcm.x+vcm.y*vcm.y));

		fi+=omega*rw.dt;

	}

	public Point3D getBackCenter(){

		double sinf=Math.sin(fi);
		double cosf=Math.cos(fi);	

		return new Point3D(cm.x-semiLen*cosf,cm.y-semiLen*sinf,0);	

	}

	public Point3D calculateFrontLinePosition(boolean isCheckWidth) {


		double pos=-1;

		double sinf=Math.sin(fi);
		double cosf=Math.cos(fi);		

		Point3D center_f=new Point3D(cm.x+semiLen*cosf,cm.y+semiLen*sinf,0);


		Point3D wheel_lf=new Point3D(center_f.x+semiWidth*sinf,center_f.y-semiWidth*cosf,0);
		Point3D wheel_rf=new Point3D(center_f.x-semiWidth*sinf,center_f.y+semiWidth*cosf,0);

		double current_pos=-1;
		Point3D current_intersection=null;

		for (int j = 0; j < rw.tracks.length; j++) {
			
			Track tr=rw.tracks[j];

			Point3D p0=new Point3D(tr.start.x,tr.start.y,0);
			Point3D p1=new Point3D(tr.end.x,tr.end.y,0);

			Point3D intersection=calculateLineIntersection(
					wheel_lf,wheel_rf,p0,p1,isCheckWidth
					);



			if(intersection!=null){

				pos=distance(center_f.x,center_f.y,intersection.x,intersection.y);

			
				if(!isCheckWidth){
					
					if(current_pos<0 || pos<current_pos){
						
						current_pos=pos;
						current_intersection=intersection;
						
					}
					
				}
				else if(pos>semiWidth)
					return null;
				else
					return intersection;
				//System.out.println(intersection.x+","+intersection.y);

			}

		}




		return current_intersection;
	}

	public Point3D calculateBackLinePosition(boolean isCheckWidth) {


		double pos=-1;

		double sinf=Math.sin(fi);
		double cosf=Math.cos(fi);		

		Point3D center_b=new Point3D(cm.x-semiLen*cosf,cm.y-semiLen*sinf,0);



		Point3D wheel_lb=new Point3D(center_b.x+semiWidth*sinf,center_b.y-semiWidth*cosf,0);
		Point3D wheel_rb=new Point3D(center_b.x-semiWidth*sinf,center_b.y+semiWidth*cosf,0);


		double current_pos=-1;
		Point3D current_intersection=null;

		for (int j = 0; j < rw.tracks.length; j++) {
			
			Track tr=rw.tracks[j];

			Point3D p0=new Point3D(tr.start.x,tr.start.y,0);
			Point3D p1=new Point3D(tr.end.x,tr.end.y,0);

			Point3D intersection=calculateLineIntersection(
					wheel_lb,wheel_rb,p0,p1,isCheckWidth
					);

		

			if(intersection!=null){
				
				pos=distance(center_b.x,center_b.y,intersection.x,intersection.y);

				if(!isCheckWidth){
					
					if(current_pos<0 || pos<current_pos){
						
						current_pos=pos;
						current_intersection=intersection;
						
					}
					
				}
				else if(pos>semiWidth)
					return null;
				else
					return intersection;
				//System.out.println(intersection.x+","+intersection.y);

			}

		}




		return current_intersection;
	}


	private double distance(double x0, double y0, double x1, double y1) {

		return Math.sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));
	}


	private Point3D calculateLineIntersection(Point3D p1,Point3D p2,Point3D p3,Point3D p4, boolean isCheckWidth) {


		double det=(p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y);
		double ua=(p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x);
		double ub=(p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x);

		if(det==0)
			return null;

		double xx=p1.x+ua/det*(p2.x-p1.x);
		double yy=p1.y+ua/det*(p2.y-p1.y);



		Point3D intersection=new Point3D(xx,yy,0);
		
		
		if (intersection.x < Math.min(p3.x,p4.x) || intersection.x  > Math.max(p3.x,p4.x))
			return null;

		if (intersection.y < Math.min(p3.y,p4.y) || intersection.y  > Math.max(p3.y,p4.y))
			return null;


		if(isCheckWidth){
		
			if (intersection.x < Math.min(p1.x,p2.x) || intersection.x  > Math.max(p1.x,p2.x))
				return null;
	
			if (intersection.y < Math.min(p1.y,p2.y) || intersection.y  > Math.max(p1.y,p2.y))
				return null;
			
		}

		return intersection;
	}

	public static Vector getWagonTypesList() {
	
		Vector values=new Vector();
		for (int i = 0; i < WAGONS_DATA.length; i++) {
			
			String val=""+WAGONS_DATA[i].wagon_type;
			values.add(new ValuePair(val,val));
	
		}
		
		return values;
	}

	public int getWagon_type() {
		return wagon_type;
	}

	public void setWagon_type(int wagon_type) {
		
		this.wagon_type = wagon_type;
		
		this.wagonImage=WAGONS_DATA[this.wagon_type].wagonImage;
		this.semiLen=WAGONS_DATA[this.wagon_type].semiLen;
		this.semiWidth=WAGONS_DATA[this.wagon_type].semiWidth;
		
		INVERSE_I=12.0/(4*semiLen*semiLen*mass);
	}

	public static ImageIcon[] getWagonImages() {
	
		 ImageIcon[] icons=new  ImageIcon[WAGONS_DATA.length];
		 
		 for (int i = 0; i < icons.length; i++) {
			
			 
			 icons[i]=new ImageIcon(WAGONS_DATA[i].wagonImage);
		}
		
		return icons;
	}

}
